/*
	This a plugin for website to use World Bank data easily, 
	especially to add data visualization to plain text.

	author: Chengye Zhao <chengyezhao@gmail.com>
*/

DEBUG = false;


/*library begin*/
var $hl_plugin_base = {

	//simple ajax lib
	$ajax : {
		getRequestObject : function() {
			var request = null;
			try {
				request = new XMLHttpRequest();
			} catch (trymicrosoft) {
				try {
					request = new ActiveXObject("Msxml2.XMLHTTP");
				} catch (othermicrosoft) {
					try {
						request = new ActiveXObject("Microsoft.XMLHTTP");
					} catch (failed) {
						request = false;
					}  
				}
			}
			return request;
		},

		load_by_request: function(request, url, handle, cached){
			if(request){
				request.open("GET", url, true);
				if(!cached)
					request.setRequestHeader("If-Modified-Since","0");
				request.onreadystatechange = function(){
					if(request.readyState == 4){
						if(request.status == 200){
							handle(true, request.responseText);
							return;
						}
					}
				};
				request.send();
			}
		},

		load: function(url, handle, cached){
			var request = this.getRequestObject(cached);
			if(request){
				request.open("GET", url, true);
				if(!cached) request.setRequestHeader("If-Modified-Since","0");
				request.onreadystatechange = function(){
					if(request.readyState == 4){
						if(request.status == 200){
							handle(true, request.responseText);
							return;
						}
					}
				};
				request.send();
			}
		},

		post: function(url, postStr, handle){
			var request = this.getRequestObject();
			if(request){
				request.open("POST", url, true);
				request.onreadystatechange = function(){
					if(request.readyState == 4){
						if(request.status == 200){
							handle(true, request.responseText);
							return;
						}
					}
				};
				request.send(postStr);
			}
		}
	},


	//get element by selector, such as ".className", "body", "#idName"
	$getElementsBySelector: function(all_selectors){
		//Get DOM elements based on the given CSS Selector - V 1.00.A Beta
		//http://www.openjs.com/scripts/dom/css_selector/
		var selected = new Array();
		if(!document.getElementsByTagName) return selected;
		all_selectors = all_selectors.replace(/\s*([^\w])\s*/g,"$1");//Remove the 'beutification' spaces
		var selectors = all_selectors.split(","); //support selectors such as "div#news, span.sports"
		// Grab all of the tagName elements within current context	
		var getElements = function(context,tag) {
			if (!tag) tag = '*';
			// Get elements matching tag, filter them for class selector
			var found = new Array;
			for (var a=0,len=context.length; con=context[a],a<len; a++) {
				var eles;
				if (tag == '*') eles = con.all ? con.all : con.getElementsByTagName("*");
				else eles = con.getElementsByTagName(tag);
				for(var b=0,leng=eles.length;b<leng; b++) found.push(eles[b]);
			}
			return found;
		}

		COMMA:
		for(var i=0,len1=selectors.length; selector=selectors[i],i<len1; i++) {
			var context = new Array(document);
			var inheriters = selector.split(" ");

			SPACE:
			for(var j=0,len2=inheriters.length; element=inheriters[j],j<len2;j++) {
				//This part is to make sure that it is not part of a CSS3 Selector
				var left_bracket = element.indexOf("[");
				var right_bracket = element.indexOf("]");
				var pos = element.indexOf("#");//ID
				if(pos+1 && !(pos>left_bracket&&pos<right_bracket)) {
					var parts = element.split("#");
					var tag = parts[0];
					var id = parts[1];
					var ele = document.getElementById(id);
					if(!ele || (tag && ele.nodeName.toLowerCase() != tag)) { //Specified element not found
						continue COMMA;
					}
					context = new Array(ele);
					continue SPACE;
				}

				pos = element.indexOf(".");//Class
				if(pos+1 && !(pos>left_bracket&&pos<right_bracket)) {
					var parts = element.split('.');
					var tag = parts[0];
					var class_name = parts[1];

					var found = $hl_plugin_base.$getElements(context,tag);
					context = new Array;
					for (var l=0,len=found.length; fnd=found[l],l<len; l++) {
						if(fnd.className && fnd.className.match(new RegExp('(^|\s)'+class_name+'(\s|$)'))) context.push(fnd);
					}
					continue SPACE;
				}

				if(element.indexOf('[')+1) {
					//If the char '[' appears, that means it needs CSS 3 parsing
					// Code to deal with attribute selectors
					if (element.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?['"]?([^\]'"]*)['"]?\]$/)) {
						var tag = RegExp.$1;
						var attr = RegExp.$2;
						var operator = RegExp.$3;
						var value = RegExp.$4;
					}
					var found = $hl_plugin_base.$getElements(context,tag);
					context = new Array;
					for (var l=0,len=found.length; fnd=found[l],l<len; l++) {
						if(operator=='=' && fnd.getAttribute(attr) != value) continue;
						if(operator=='~' && !fnd.getAttribute(attr).match(new RegExp('(^|\\s)'+value+'(\\s|$)'))) continue;
						if(operator=='|' && !fnd.getAttribute(attr).match(new RegExp('^'+value+'-?'))) continue;
						if(operator=='^' && fnd.getAttribute(attr).indexOf(value)!=0) continue;
						if(operator=='$' && fnd.getAttribute(attr).lastIndexOf(value)!=(fnd.getAttribute(attr).length-value.length)) continue;
						if(operator=='*' && !(fnd.getAttribute(attr).indexOf(value)+1)) continue;
						else if(!fnd.getAttribute(attr)) continue;
						context.push(fnd);
					}

					continue SPACE;
				}

				//Tag selectors - no class or id specified.
				var found = $hl_plugin_base.$getElements(context,element);
				context = found;
			}
			for (var o=0,len=context.length;o<len; o++) selected.push(context[o]);
		}
		return selected;
	},

	$getElements : function(context,tag) {
		if (!tag) tag = '*';
		// Get elements matching tag, filter them for class selector
		var found = new Array;
		for (var a=0,len=context.length; con=context[a],a<len; a++) {
			var eles;
			if (tag == '*') eles = con.all ? con.all : con.getElementsByTagName("*");
			else eles = con.getElementsByTagName(tag);
			for(var b=0,leng=eles.length;b<leng; b++) found.push(eles[b]);
		}
		return found;
	},

	$hashtable : function ()
	{
		this.length = 0;
		this.items = new Array();
		for (var i = 0; i < arguments.length; i += 2) {
			if (typeof(arguments[i + 1]) != 'undefined') {
				this.items[arguments[i]] = arguments[i + 1];
				this.length++;
			}
		}

		this.removeItem = function(in_key)
		{
			var tmp_previous;
			if (typeof(this.items[in_key]) != 'undefined') {
				this.length--;
				var tmp_previous = this.items[in_key];
				delete this.items[in_key];
			}

			return tmp_previous;
		}

		this.getItem = function(in_key) {
			return this.items[in_key];
		}

		this.setItem = function(in_key, in_value)
		{
			var tmp_previous;
			if (typeof(in_value) != 'undefined') {
				if (typeof(this.items[in_key]) == 'undefined') {
					this.length++;
				}
				else {
					tmp_previous = this.items[in_key];
				}

				this.items[in_key] = in_value;
			}

			return tmp_previous;
		}

		this.hasItem = function(in_key)
		{
			return typeof(this.items[in_key]) != 'undefined';
		}

		this.clear = function()
		{
			for (var i in this.items) {
				delete this.items[i];
			}

			this.length = 0;
		}
	},

	// Insert node after one node
	$insertAfter: function( referenceNode, newNode )
	{
		referenceNode.parentNode.insertBefore( newNode, referenceNode.nextSibling );
	},

	// Add multi-load event
	$addLoadEvent: function (func) {
		var oldonload = window.onload;
		if (typeof window.onload != 'function') {
			window.onload = func;
		} else {
			window.onload = function() {
				if (oldonload) {
					oldonload();
				}
				func();
			}
		}
	},

	//find the pos of one element 
	$findPos : function(obj){
		var curleft = curtop = 0;
		if(obj.offsetParent){
			do{
				curleft += obj.offsetLeft;
				curtop += obj.offsetTop;
			}while(obj = obj.offsetParent);
		}
		return {x: curleft, y: curtop};
	},

	//find the pos of the event
	$get_event_pos: function(e) {
		var posx = 0;
		var posy = 0;
		if(!e) e = window.event;
		if (e.pageX || e.pageY) 	{
		posx = e.pageX;
		posy = e.pageY;
		}
		else if (e.clientX || e.clientY) 	{
		posx = e.clientX + document.body.scrollLeft
		+ document.documentElement.scrollLeft;
		posy = e.clientY + document.body.scrollTop
		+ document.documentElement.scrollTop;
		}
		return {x: posx, y: posy, xc: e.clientX, yc: e.clientY};
	},

};
/*library end*/

/*plugin begin*/
var $hl_plugin = {

	//where to find keyword, default <body> element 
	selector: "body",

	//is keyword case sensitive, default False
	case_sen: false,

	//find only the firt apperance of the certain keyword or not
	// support "first", "all"
	mode: "all", 

	//keyword array, default null
	keywords: null, 

	map: new $hl_plugin_base.$hashtable(),

	keyword_table_by_context: new Array(),
	
	//keyword url
	resource_url: '', 

	//registered plugins
	plugins: new Array(),


	//help function to add plugin
	extend: function(plugin){ this.plugins.push(plugin);	},

	get_keyword: function(){ return this.keywords; },
	

	//set configuration
	setup: function(config){

		//check input config parameters
		if(config != null && config != undefined){

			if(config.selector != null && config.selector != undefined){
				this.selector = String(config.selector);
			}

			if(config.mode != null && config.mode != undefined){
				this.mode = String(config.mode);
			}
	
			if(config.case_sen != null && config.mode != undefined){
				this.case_sen = !!config.case_sen;
			}

			if(config.keywords != null && config.keywords != undefined ){
				this.processKeywords(config.keywords);
			}

			if(config.resource_url != null && config.resource_url != undefined){
				this.resource_url = config.resource_url;
			}
		}

		for(ind in this.plugins){ this.plugins[ind].setup(config, this); }

		//remote load keywords
		this.remote_load( this.after_load ); 
	},


	//load resource 
	remote_load: function(handle){
		var obj = this;
		$hl_plugin_base.$addLoadEvent(function (){
			if(obj.keywords == null){

				var url = obj.resource_url;

				$hl_plugin_base.$ajax.load(url, function(responseStatus, responseText){

					if(handle != null && handle != undefined) {
						handle(obj, responseStatus, responseText);
					}

				}, true);	

			}else{ handle(obj, true, null); }

		});
	},


	//after all resources are loaded from remote server
	after_load : function(obj, status_code, resource){

		//try to load keywords array if necessary
		if(status_code == false) return;
		if(obj.keywords == null){
			try{
				eval("var keywords = " + resource);
			}catch(err){
				return;
			}
			obj.processKeywords(keywords);
		}
		if(!obj.keywords) return;

		//process keywords array to hashtable
		var keywordTable = null;
		if(obj.case_sen)
			keywordTable = obj.get_hash_table(obj.keywords);
		else
			keywordTable = obj.get_hash_table(obj.keywords, false);

		//elements queue
		var elements = $hl_plugin_base.$getElementsBySelector(obj.selector);
		while(elements.length > 0){
			var context = elements.shift();
			//get the child nodes of current context
			var context_children = context.childNodes;
			for(ind in context_children){
				//if the node is a text node
				if(context_children[ind].nodeType == 3){
					var keyword_found = obj.process_text_node(context_children[ind].nodeValue, keywordTable);
					if(keyword_found.length > 0){
						obj.keyword_table_by_context.push({
							found: keyword_found,
							child: context_children[ind], 
							context_string: context_children[ind].nodeValue
						});
					}
				}else{
					//if current node is not a text node
					elements.push(context_children[ind]);
				}
			}
		}
		for(ind in obj.keyword_table_by_context){
			var table_item = obj.keyword_table_by_context[ind];
			for(jnd  in obj.plugins){
				obj.plugins[jnd].process_by_context(table_item.context_string, table_item.child, table_item.found);
			}
		}
		for(jnd in obj.plugins){
			obj.plugins[jnd].process_all(obj.keyword_table_by_context);
		}
	},

	processKeywords: function(keywords) {
		this.keywords = new Array();
		for(var i = 0; i < keywords.length / 2; i++){
			this.keywords.push(keywords[2 * i]);
			this.map.setItem(keywords[2 * i].toLowerCase(), keywords[2 * i + 1]);
		}
	},


	get_hash_table: function(keywords, case_sen){
		if(case_sen == null || case_sen == undefined) case_sen = true;
		var table = new $hl_plugin_base.$hashtable(); 
		for(ind in keywords){
			if(case_sen)
				table.setItem(keywords[ind], ind);
			else
				table.setItem(keywords[ind].toLowerCase(), ind);
		}
		return table;
	},

	process_text_node: function(context_str, keywordTable){
		//try to find keyword in this text node
		var pos = 0;
		var keyword_found = new Array();
		NEXTPOS:
		while(pos >= 0){
			var rets = this.get_keyword_tokens(context_str, pos);
			if(rets.length == 0)
				break NEXTPOS;
			KEYWORDS:
			for(jnd in rets){
				var keyword = rets[jnd].keyword;
				if(keyword){
					//case sensentive
					if(this.case_sen){
						if(keywordTable.hasItem(keyword)){
							keyword_found.push({word: keyword, position: rets[jnd].currentPos});
							if(this.mode == "first")
								keywordTable.removeItem(keyword);
							break KEYWORDS;
						}
					}else{
						//case not sensentive
						if(keywordTable.hasItem(keyword.toLowerCase())){
							keyword_found.push({word: keyword, position: rets[jnd].currentPos});
							if(this.mode == "first")
								keywordTable.removeItem(keyword.toLowerCase());
							break KEYWORDS;
						}
					}
				}
			}
			pos = rets[0].nextPos;
			continue NEXTPOS;
		}
		return keyword_found;
	},

	get_keyword_tokens: function(text, pos){
		var delimiter = " \'\",;.:?~!@#$%^&*()_+<>\/\\|=-\t\n";
		var len = text.length;
		var ret = new Array();
		var keyword_array = new Array(); 

		var max_count = 3;
		while(pos < len){
			if(delimiter.indexOf(text[pos]) >= 0){
				++pos;
			}else{
				break;
			}
		}
		if(pos >= len){
			return ret;
		}
		var start_pos = pos;
		COUNT:
		for(var i = 0; i < max_count; i++){
			while(pos < len){
				if(delimiter.indexOf(text[pos]) >= 0){
					++pos;
				}else{
					break;
				}
			}
			if(pos >= len){
				break COUNT;
			}
			var temp_pos = pos;
			while(pos < len){
				if(delimiter.indexOf(text[pos]) < 0){
					++pos;
				}else{
					break;
				}
			}
			keyword_array.push(text.substring(temp_pos, pos));
			if(pos < len){
				ret.push({nextPos: pos, currentPos: start_pos, keyword: keyword_array.join(' ')});
			}else{
				ret.push({nextPos: -1, currentPos: start_pos, keyword: keyword_array.join(' ')});
			}
		}
		return ret;
	}
};

//register the default plugin, which highlight keywords 
$hl_plugin.extend({


	//when to show pop-up box, default mouseover
	pop_event: "mouseover",

	//keyword CSS style, default null
	keyword_style: null, 

	popup_window : null,
	_keyword_class : "ex-plugin-keyword",
	_popbox_class: "ex-plugin-popup-window",
	_popup_close_class: "ex-plugin-popup-close",
	_popup_loading_class : "ex-plugin-popup-loading",
	_popup_tri_class: "ex-plugin-triangle",
	_popup_tri_class_top: "ex-plugin-triangle-top",
	_popbox_class_after_load: "ex-plugin-popup-window-after-load",
	_popup_close_class_after_load: "ex-plugin-popup-close-after-load",
	_popup_tri_class_after_load: "ex-plugin-triangle-after-load",
	_popup_delay : 500,
	_popup_request: null, 
	_popup_clock: null,
	_popup_tri: null,
	_popup_close: null,
	_popup_loading: null,
	_indicate_name_class : "ex-plugin-indicate-name",
	_indicate_value_class : "ex-plugin-indicate-value",

	_proxy_url: DEBUG?'http://localhost:8080/':'http://hl-demo-for-worldbank.appspot.com/', 

	plugin_base: null,
	
	indicator_title : ['GDP, total(current US$)', 'Population, total', 'Life expectancy at birth, total', 'Environment CO2 emissions (Kt)'],
	indicator_id: ['NY.GDP.MKTP.CD', 'SP.POP.TOTL', 'SP.DYN.LE00.IN', 'EN.ATM.CO2E.KT'],
	
	resource : null,

	/*setup, process_by_context, process_all are interfaces musct be implemented by plugin*/

	//interface to outside users
	setup : function (config, base) {

		this.plugin_base = base;

		//check input config parameters
		if(config != null && config != undefined){


			if(config.style != null && config.style != undefined){
				this.keyword_style = config.style;
			}

			if(config.pop_event != null && config.pop_event != undefined){
				this.pop_event = config.pop_event;
			}
		}
	},

	process_by_context: function(context, child_node, keyword_found){
		var last_node = child_node;
		var last_pos = 0; 
		for(ind in keyword_found){
			var pos =  keyword_found[ind].position;
			if(pos > last_pos){
				//text_node
				var text_node = document.createTextNode(context.substring(last_pos, pos));
				$hl_plugin_base.$insertAfter(last_node, text_node);
				last_node = text_node;
			}
			//keyword node
			var keyword_node= document.createElement('a');
			keyword_node.innerHTML = keyword_found[ind].word;
			keyword_node.href = "javascript:void(0)";
			keyword_node.className = this._keyword_class;
			//regisiter event
			var obj = this;
			try{
				if(this.pop_event == "click")
					keyword_node.onclick = function(e){
						obj.pop_function(this,e);
					}
				else
					keyword_node.onmouseover = function(e){
						obj.pop_function(this,e);
					}
				/*keyword_node.addEventListener(
					this.pop_event, 
					function () {obj.pop_function(this);},
					true
				);*/
			}catch(e){
			}
			if(this.keyword_style){
				for(jnd in this.keyword_style){
					keyword_node.style[jnd] = this.keyword_style[jnd];
				}
			}
			$hl_plugin_base.$insertAfter(last_node, keyword_node);
			//next
			last_node = keyword_node;
			last_pos = pos + keyword_found[ind].word.length;
		}
		if(last_pos < context.length){
			var text_node = document.createTextNode(context.substring(last_pos, context.length));
			$hl_plugin_base.$insertAfter(last_node, text_node);
		}
		child_node.parentNode.removeChild(child_node);
	},

	process_all: function(keyword_table_by_context){
	},


	/* interface define end */

	//get the default popup window
	get_default_popup_window: function(){
		if(this.popup_window == null){
			this.popup_window = document.createElement('div');
			this.popup_window.className = this._popbox_class;
		}else{
			this.close_pop_window();
		}

		var tr = document.createElement('div');
		tr.className = this._popup_tri_class;
		var i = document.createElement('span');
		i.className = "bor";
		var j = document.createElement('span');
		j.className = 'blo';
		tr.appendChild(i);
		tr.appendChild(j);
		this.popup_window.appendChild(tr);
		this._popup_tri = tr;

		var close_node = document.createElement('div');
		close_node.className = this._popup_close_class; 
		close_node.href = "javascript:void(0)";
		var obj = this; /*close_node.addEventListener('click', function(){
			obj.close_pop_window();
		}, true);*/
		close_node.onclick = function (){
			obj.close_pop_window();
		};
		this.popup_window.appendChild(close_node);
		this._popup_close = close_node;

		var loading_node = document.createElement('div');
		loading_node.className = this._popup_loading_class; 
		this.popup_window.appendChild(loading_node);
		this._popup_loading = loading_node;

		this.setPopBeforeLoad();

		return this.popup_window;
	},

	get_default_popup_request: function(){
		if(this._popup_request == null){
			this._popup_request = $hl_plugin_base.$ajax.getRequestObject();
		}
		return this._popup_request;
	},

	get_country_request_url : function(name){
		return this._proxy_url + "api.worldbank.org/countries/"+ name +"?format=json";
	},

	get_indicator_request_url : function(name, indicator_name){
		return this._proxy_url + "api.worldbank.org/countries/"+ name +"/indicators/"+ indicator_name +"?format=json&date=1990:2009";
	},

	close_pop_window: function(){
		try{
			this.popup_window.style.display = "none";
			this.popup_window.innerHTML = "";
			if(this.popup_window.parentNode)
				this.popup_window.parentNode.removeChild(this.popup_window);
			this._popup_request.abort();
			this.temp_el = null;
		}catch(e){}
	},

	pop_function: function(el, e){
		var obj = this;
		this._popup_clock = setTimeout(function () {
			obj.pop_after_delay(el, e);	
		}, this._popup_delay);
		if(obj.pop_event == 'mouseover'){
			el.onmouseout = function(){
				clearTimeout(obj._popup_clock);
				obj._popup_clock = null;
			}
		}
	},

	temp_el : null,
	pop_after_delay: function(el, e){
		if(this.temp_el == el) return;
		var name = this.plugin_base.map.getItem(el.text.toLowerCase());
		//get the pop up window, load resource, and set up content
		this.popup_window = this.get_default_popup_window();
		$hl_plugin_base.$insertAfter(el, this.popup_window);
		var posc = $hl_plugin_base.$get_event_pos(e); 
		var obj = this; $hl_plugin_base.$ajax.load_by_request(
			this.get_default_popup_request(),
			this.get_country_request_url(name),
			function(responseStatus, responseText){
				if(responseStatus){
					obj.setPopAfterLoad();
					obj.setPopPosition(el, posc);
					eval("var resource = " + responseText );
					obj.resource = resource[1][0];
					obj.setupWindow(name, obj.popup_window,el);
				}
			}, true
		);
		this.temp_el = el;

		//set position of the pop up window
		this.setPopPosition(el, posc);
	},

	setupWindow: function(name, win, el){
		var mapdiv = document.createElement('div');
		mapdiv.className = 'ex-plugin-map-window';
		win.appendChild(mapdiv);
		var script = document.createElement("script");
		script.type = "text/javascript";
		script.src = "http://maps.google.com/maps/api/js?sensor=false&callback=setupMap";
		document.body.appendChild(script);
		var obj = this;
		this.resource.indicates = new $hl_plugin_base.$hashtable();
		for(ind in this.indicator_id){
			eval('var f = function(responseStatus, responseText){ eval("var indicator_json = " + responseText); try{ obj.resource.indicates.setItem(obj.indicator_title['+String(ind)+'], indicator_json[1]); }catch(e){ obj.resource.indicates.setItem(obj.indicator_title['+String(ind)+'],{}); } }');
			eval('$hl_plugin_base.$ajax.load(obj.get_indicator_request_url(name, obj.indicator_id['+ String(ind)+']), f , true);');
		}
		setupMap = function() {
			var latlng = new google.maps.LatLng(parseFloat(obj.resource.latitude), parseFloat(obj.resource.longitude));
			var myOptions = {
				zoom: 2,
				center: latlng,
				streetViewControl: false,
				mapTypeControl: false,
				mapTypeId: google.maps.MapTypeId.ROADMAP 
			};
			var map = new google.maps.Map(mapdiv, myOptions);
			var marker = new google.maps.Marker({map: map, position:
			map.getCenter()});
			google.maps.event.addListener(marker, 'click', function() {
				mapdiv.style.display = 'none';
				var content = document.createElement('div');
				content.className = 'ex-plugin-content-window';
				var check =self.setInterval(function(){
					if(obj.temp_el != el){
						clearInterval(check);
						return;
					}
					if(obj.resource.indicates.length == obj.indicator_id.length){
						obj._popup_loading.style.display = "none";
						obj._popup_loading.className = "ex-plugin-popup-loading";
						content.innerHTML = obj.getHTMLfromResource(obj.resource); 
						win.appendChild(content); 
						clearInterval(check);
					}else{ 
						obj._popup_loading.className = "ex-plugin-popup-loading-after-load";
						obj._popup_loading.style.display = "block";
					}
				},50);
			});
		};
	},

	getHTMLfromResource: function(resource){
		var s = '';
		resource.region.value = resource.region.value.replace(/\(.*\)/, "");
		s += '<div class="ex-plugin-content-window">';
		s += '<div class="ex-plugin-info-title">';
	 	s += '<a href="http://data.worldbank.org/country/' + resource.iso2Code + '" target="_blank">' + resource.name + '</a>';
		s += '</div>';
		s += '<div style="clear:both"></div>';
		s += '<div class="ex-plugin-info-float-block">';
		s += '<div class="p1">Regin</div>';
		s += '<div class="p2"><a href="http://data.worldbank.org/region/' + resource.region.id + '" target="_blank">' + resource.region.value + '</a></div>';
		s += '</div>';
		s += '<div class="ex-plugin-info-float-block">';
		s += '<div class="p1">Income level</div>';
		s += '<div class="p2">'+ resource.incomeLevel.value + '</div>';
		s += '</div>';
		for(ind in this.indicator_title){
			var indicates = resource.indicates.getItem(this.indicator_title[ind]);
			for(jnd in indicates){
				if(indicates[jnd].value == null){
				}else{
					break;
				}
			}
			var indicate = indicates[jnd];
			s += '<div class="ex-plugin-info-float-block">';
			s += '<div class="p1">' + this.indicator_title[ind] + '</div>';
			try{
				s += '<div class="p2"><a href="http://data.worldbank.org/indicator/' + indicate.indicator.id + '/countries/' + resource.iso2Code +  '?display=graph" target="_blank">' + this.addCommas(String(parseFloat(indicate.value).toFixed(2))) +  '</a><span class="p3">' + indicate.date + '</span></div>';
			}catch(e){
				s += '<div class="p2">Data not avaliable</div>';
			}
			s += '</div>';
		}
		s += '<div class="ex-plugin-info-copyright">Data from World Bank</div>';
		s += '</div>';
		s += '</div>';
		return s;
	},

	addCommas: function(nStr)
	{
		nStr += '';
		x = nStr.split('.');
		x1 = x[0];
		x2 = x.length > 1 ? '.' + x[1] : '';
		var rgx = /(\d+)(\d{3})/;
		while (rgx.test(x1)) {
			x1 = x1.replace(rgx, '$1' + ',' + '$2');
		}
		return x1 + x2;
	},

	setPopBeforeLoad: function(){
		this.popup_window.className = this._popbox_class; 
		this._popup_tri.className = this._popup_tri_class; 
		this._popup_loading.style.display = "block";
		this._popup_close.className = this._popup_close_class; 
		this.popup_window.style.display = "block";
	},

	setPopAfterLoad: function(){
		this.popup_window.className += " " + this._popbox_class_after_load;
		this._popup_tri.className += " " + this._popup_tri_class_after_load; 
		this._popup_loading.style.display = "none";
		this._popup_close.className +=  " " + this._popup_close_class_after_load; 
		this.popup_window.style.display = "block";
	},

	setTriTop: function(){
		this._popup_tri.className = this._popup_tri_class_top; 
	},

	setPopPosition: function(el, posc){
		var pos = $hl_plugin_base.$findPos(el);
		var pos_left = pos.x - this.popup_window.clientWidth/2; 
		var pos_right = pos.x + this.popup_window.clientWidth/2; 
		var clientWidth = $hl_plugin_base.$getElementsBySelector('body')[0].clientWidth; 
		var clientHeight = $hl_plugin_base.$getElementsBySelector('body')[0].clientHeight; 
		var windowWidth	= this.popup_window.clientWidth; 
		var windowHeight = this.popup_window.clientHeight; 
		//if(posc.yc -  windowHeight - 35 >= 0){
		if(posc.yc -  250 - 35 >= 0){
			this.popup_window.style.top = (pos.y - windowHeight - 25) + "px";
		}else{
			this.popup_window.style.top = (pos.y + 35) + "px";
			this.setTriTop();
		}
		if(pos_left < 0) 
			pos_left = 0;
		if(pos_right > clientWidth)
			pos_left = clientWidth - this.popup_window.clientWidth;  	
		this.popup_window.style.left = pos_left  + "px";
		if(pos.x - pos_left + 40 > this.popup_window.clientWidth) {
			this._popup_tri.style.left = (this.popup_window.clientWidth - 40) + "px";
		}else{
			this._popup_tri.style.left = (pos.x - pos_left) + "px";
		}
	}
});
